package com.eastfair.tag.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.annotation.base.SubjectTypeEnum;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.base.entity.SuperEntity;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.code.ExceptionCode;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.core.utils.StringUtils;
import com.eastfair.tag.dao.TagMapper;
import com.eastfair.tag.dto.TagDTO;
import com.eastfair.tag.dto.TagPageQuery;
import com.eastfair.tag.entity.Tag;
import com.eastfair.tag.enumeration.TagTypeEnum;
import com.eastfair.tag.service.TagService;
import com.eastfair.tag.vo.TagVO;
import com.eastfair.util.CodeUtils;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 标签表
 * </p>
 *
 * @author zjn
 * @date 2022-03-02
 */
@Slf4j
@Service
@DS("#thread.tenant")
public class TagServiceImpl extends SuperServiceImpl<TagMapper, Tag> implements TagService {

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<Tag> modelList) {
        modelList.stream().forEach(s -> {
            s.setIsDeleted(BusinessConstant.YES);
        });
        // TODO: 2021/10/29 这里需要操作其他业务，如清空角色等
        return R.successDef();
    }

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(Tag model) {
        model.setId(DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId()));
        model.setProjectId(ContextUtil.getProjectId());
        if (StringUtils.isBlank(model.getCode())) {
            model.setCode(queryCode(model));
        }
        return R.successDef();
    }

    @Override
    @GlobalTransactional(name = "saveTag", rollbackFor = Exception.class)
    public R<Boolean> saveTag(TagDTO tagDTO) {
        if (Objects.isNull(tagDTO) || StringUtils.isBlank(tagDTO.getName())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        if (Objects.isNull(tagDTO.getParentId()) || BusinessConstant.parentId.equals(tagDTO.getParentId())) {
            tagDTO.setParentId(BusinessConstant.parentId);
        } else {
            // 将父节点变为根节点（分类节点） 并将父级节点的分类赋予改节点
            Boolean parentUpdateFlag = updateParentType(tagDTO, TagTypeEnum.CLASSIFY);
            if (!parentUpdateFlag) {
                return R.fail(ExceptionCode.DATA_SAVE_ERROR);
            }
        }
        if (Objects.isNull(tagDTO.getType())) {
            tagDTO.setType(TagTypeEnum.NODE);
        }
        Tag tag = BeanUtil.toBean(tagDTO, Tag.class);
        return R.success(save(tag));
    }

    @Override
    @GlobalTransactional(name = "deleteTag", rollbackFor = Exception.class)
    public R<Boolean> deleteTag(Long id) {
        if (Objects.isNull(id)) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }

        Tag tag = getById(id);
        if (Objects.isNull(tag)) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }

        // 删除标签及子节点
        UpdateWrapper<Tag> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().likeRight(Tag::getCode, tag.getCode())
                .set(Tag::getIsDeleted, BusinessConstant.DELETE_YES);
        update(updateWrapper);

        return R.success(true);
    }

    @Override
    @GlobalTransactional(name = "updateTag", rollbackFor = Exception.class)
    public R<Boolean> updateTag(TagDTO tagDTO) {
        if (Objects.isNull(tagDTO) || Objects.isNull(tagDTO.getId())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        Tag oldTag = getById(tagDTO.getId());
        if (Objects.isNull(oldTag)) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }

        Tag updateTag = BeanUtil.toBean(tagDTO, Tag.class);
        if (Objects.isNull(updateTag.getParentId())
                || oldTag.getParentId().equals(updateTag.getParentId())) {
            return R.success(updateById(updateTag));
        }
        // 父节点改变需要改变code以及所有子节点的code
        QueryWrapper<Tag> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().likeRight(Tag::getCode, oldTag.getCode())
                .eq(Tag::getIsDeleted, BusinessConstant.DELETE_NO)
                .last("ORDER BY LENGTH(CODE) - LENGTH(REPLACE(CODE, ',', '')) ASC");
        // 排序查询，第一个为根节点
        List<Tag> list = list(queryWrapper);
        if (CollectionUtil.isEmpty(list)) {
            return R.fail(ExceptionCode.SYSTEM_BUSY);
        }
        BeanUtil.copyProperties(updateTag, list.get(0));
        Long rootId = list.get(0).getId();
        // 修改父节点code及分类
        list.get(0).setCode(queryCode(list.get(0)));
        Map<Long, Tag> tagMap = list.stream().collect(Collectors.toMap(SuperEntity::getId, tag -> tag));
        tagMap.forEach((id, tag) -> {
            if (id.equals(rootId)) {
                Tag rootParentTag = getById(tag.getParentId());
                if (!Objects.isNull(rootParentTag)) {
                    tag.setSubjectType(rootParentTag.getSubjectType());
                }
            } else {
                queryCodeOfList(tag, tagMap);
            }
        });

        return R.success(updateBatchById(list));
    }

    @Override
    public R<List<TagVO>> listTreeClassify() {
        // 获取顶级节点
        Tag topTag = getTopTag();
        if (Objects.isNull(topTag) || StringUtils.isBlank(topTag.getCode())) {
            return R.success(null);
        }

        // 获取子节点
        QueryWrapper<Tag> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Tag::getIsDeleted, BusinessConstant.DELETE_NO).eq(Tag::getType, TagTypeEnum.CLASSIFY)
                .likeRight(Tag::getCode, topTag.getCode()).last("ORDER BY LENGTH(CODE) - LENGTH(REPLACE(CODE, ',', '')) ASC");
        List<Tag> list = list(queryWrapper);
        TagVO tagVO = buildTagTree(list, topTag.getCode());
        return R.success(tagVO.getChildList());
    }

    @Override
    public R<Page<TagVO>> pageList(PageParams<TagPageQuery> params) {
        Tag parentTag;
        if (Objects.isNull(params.getModel().getParentId())) {
            parentTag = getTopTag();
        } else {
            parentTag = getById(params.getModel().getParentId());
        }
        if (Objects.isNull(parentTag)) {
            return R.success(null);
        }
        QueryWrapper<Tag> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Tag::getIsDeleted, BusinessConstant.DELETE_NO).likeRight(Tag::getCode, parentTag.getCode())
                .ne(Tag::getCode, parentTag.getCode()).orderByAsc(Tag::getSequence);
        if (!StringUtils.isBlank(params.getModel().getName())) {
            queryWrapper.and(tagQueryWrapper ->
                    tagQueryWrapper.lambda().like(Tag::getName, params.getModel().getName())
                            .or().like(Tag::getEnName, params.getModel().getName()));
        }
        Page<Tag> page = page(params.buildPage(), queryWrapper);
        return R.success(ConvertUtil.convertPage(page, TagVO.class));
    }

    @Override
    public R<TagVO> listBySubjectType(String subjectType) {
        SubjectTypeEnum subjectTypeEnum = SubjectTypeEnum.get(subjectType);
        if (Objects.isNull(subjectTypeEnum)) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }
        QueryWrapper<Tag> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Tag::getIsDeleted, BusinessConstant.DELETE_NO).eq(Tag::getIsEnabled, BusinessConstant.ENABLE_YES)
                .eq(Tag::getSubjectType, subjectTypeEnum).orderByAsc(Tag::getCode);

        List<Tag> list = list(queryWrapper);
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }
        return R.success(buildTagTree(list, list.get(0).getCode()));
    }

    /**
     * 获取不重复的code
     *
     * @return
     */
    private String queryCode(Tag model) {
        String code = nonredundantCode();
        if (!Objects.isNull(model.getParentId())) {
            Tag tag = getById(model.getParentId());
            if (tag != null) {
                code = tag.getCode() + "," + code;
            }
        }
        return code;
    }

    private String nonredundantCode() {
        String code = CodeUtils.randomCode(6);
        //是否重复
        int num = queryCodeSize(code);
        if (num > 0) {
            nonredundantCode();
        }
        return code;
    }

    private int queryCodeSize(String code) {
        QueryWrapper<Tag> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isBlank(code)) {
            return 0;
        } else {
            queryWrapper.lambda().eq(Tag::getCode, code);

        }
        queryWrapper.lambda().eq(Tag::getIsDeleted, BusinessConstant.DELETE_NO);
        //排序查询
//        queryWrapper.orderByAsc("sequence");
        return count(queryWrapper);
    }

    private Boolean updateParentType(TagDTO tagDTO, TagTypeEnum tagTypeEnum) {
        if (Objects.isNull(tagDTO.getParentId()) || Objects.isNull(tagTypeEnum)) {
            return false;
        }
        Tag parentTag = getById(tagDTO.getParentId());
        if (Objects.isNull(parentTag)) {
            return false;
        }
        if (!tagTypeEnum.eq(parentTag.getType())) {
            Tag tag = Tag.builder().id(tagDTO.getParentId()).type(tagTypeEnum).build();
            updateById(tag);
        }
        tagDTO.setSubjectType(parentTag.getSubjectType());
        return true;
    }

    /**
     * 获取不重复的code,父节点在已知集合中
     *
     * @return
     */
    private void queryCodeOfList(Tag model, Map<Long, Tag> tagMap) {
        String code = nonredundantCode();
        if (!Objects.isNull(model.getParentId())) {
            Tag tag = tagMap.get(model.getParentId());
            if (tag != null) {
                code = tag.getCode() + "," + code;
                model.setSubjectType(tag.getSubjectType());
            }
        }
        model.setCode(code);
    }

    private TagVO buildTagTree(List<Tag> list, String topCode) {
        // 构建树形结构
        TagVO tagVO = null;
        for (Tag tag : list) {
            if (topCode.equals(tag.getCode())) {
                tagVO = BeanUtil.toBean(tag, TagVO.class);
                List<TagVO> childTagList = getTagChildList(list, tag.getId()).stream().sorted(Comparator.comparing(TagVO::getSequence)).collect(Collectors.toList());
                tagVO.setChildList(childTagList);
                break;
            }
        }
        return tagVO;
    }

    private List<TagVO> getTagChildList(List<Tag> list, Long parentId) {
        List<TagVO> childList = new ArrayList<>();
        for (Tag tag : list) {
            if (parentId.equals(tag.getParentId())) {
                TagVO tagVO = BeanUtil.toBean(tag, TagVO.class);
                List<TagVO> childTagList = getTagChildList(list, tag.getId()).stream().sorted(Comparator.comparing(TagVO::getSequence)).collect(Collectors.toList());
                tagVO.setChildList(childTagList);
                childList.add(tagVO);
            }
        }
        return childList;
    }

    private Tag getTopTag() {
        QueryWrapper<Tag> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Tag::getParentId, BusinessConstant.parentId).eq(Tag::getIsDeleted, BusinessConstant.DELETE_NO);
        return getOne(queryWrapper);
    }

}
